home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Info / For Developers / GhostScript 5.10 / MacGS-510 / files / gs_setpd.ps < prev    next >
Text File  |  1997-09-30  |  21KB  |  668 lines

  1. %    Copyright (C) 1994, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % The current implementation of setpagedevice has the following limitations:
  16. %    - It doesn't attempt to "interact with the user" for Policy = 2.
  17.  
  18. languagelevel 1 .setlanguagelevel
  19. level2dict begin
  20.  
  21. % ---------------- Redefinitions ---------------- %
  22.  
  23. % Redefine .beginpage and .endpage so that they call BeginPage and
  24. % EndPage respectively if appropriate.
  25.  
  26. % We have to guard against the BeginPage procedure not popping its operand.
  27. % This is really stupid, but the Genoa CET does it.
  28. /.beginpage        % - .beginpage -
  29.  { .currentshowpagecount
  30.     { .currentpagedevice pop /BeginPage .knownget
  31.        {    % Stack: ... pagecount proc
  32.      count 2 .execn
  33.         % Stack: ... ..???.. oldcount
  34.      count 1 add exch sub { pop } repeat
  35.        }
  36.        { pop
  37.        }
  38.       ifelse
  39.     }
  40.    if
  41.  } bind odef
  42.  
  43. % Guard similarly against EndPage not popping its operand.
  44. /.endpage        % <reason> .endpage <print_bool>
  45.  { .currentshowpagecount
  46.     { 1 index .currentpagedevice pop /EndPage .knownget
  47.        {    % Stack: ... reason pagecount reason proc
  48.      count 2 .execn
  49.         % Stack: ... ..???.. print oldcount
  50.      count 2 add exch sub { exch pop } repeat
  51.        }
  52.        { pop pop 2 ne
  53.        }
  54.       ifelse
  55.     }
  56.     { 2 ne
  57.     }
  58.    ifelse
  59.  } bind odef
  60.  
  61. % Define interpreter callouts for handling gstate-saving operators,
  62. % to make sure that they create a page device dictionary for use by
  63. % the corresponding gstate-restoring operator.
  64. % We'd really like to avoid the cost of doing this, but we don't see how.
  65. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  66. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  67. % interpreter.
  68.  
  69. (%gsavepagedevice) cvn
  70.  { currentpagedevice pop gsave
  71.  } bind def
  72.  
  73. (%savepagedevice) cvn
  74.  { currentpagedevice pop save
  75.  } bind def
  76.  
  77. (%gstatepagedevice) cvn
  78.  { currentpagedevice pop gstate
  79.  } bind def
  80.  
  81. (%copygstatepagedevice) cvn
  82.  { currentpagedevice pop copy
  83.  } bind def
  84.  
  85. (%currentgstatepagedevice) cvn
  86.  { currentpagedevice pop currentgstate
  87.  } bind def
  88.  
  89. % Define interpreter callouts for handling gstate-restoring operators
  90. % when the current page device needs to be changed.
  91. % The names %grestorepagedevice, %grestoreallpagedevice,
  92. % %restorepagedevice, and %setgstatepagedevice are known to the interpreter.
  93.  
  94. /.installpagedevice
  95.  {    % Since setpagedevice doesn't create new device objects,
  96.     % we must (carefully) reinstall the old parameters in
  97.     % the same device.
  98.    .currentpagedevice pop null currentdevice null .trysetparams
  99.    dup type /booleantype eq
  100.     { pop pop }
  101.     {        % This should never happen!
  102.       DEBUG { (Error in .trysetparams!\n) print pstack flush } if
  103.       cleartomark pop pop pop
  104.       /.installpagedevice cvx /rangecheck signalerror
  105.     }
  106.    ifelse pop pop
  107.    erasepage initgraphics .beginpage
  108.  } bind def
  109.  
  110. /.uninstallpagedevice
  111.  { 2 .endpage { .currentnumcopies false .outputpage } if
  112.    nulldevice
  113.  } bind def
  114.  
  115. (%grestorepagedevice) cvn
  116.  { .uninstallpagedevice grestore .installpagedevice
  117.  } bind def
  118.  
  119. (%grestoreallpagedevice) cvn
  120.  { .uninstallpagedevice grestore .installpagedevice grestoreall
  121.  } bind def
  122.  
  123. (%restorepagedevice) cvn
  124.  { .uninstallpagedevice grestore .installpagedevice restore
  125.  } bind def
  126.  
  127. (%setgstatepagedevice) cvn
  128.  { .uninstallpagedevice setgstate .installpagedevice
  129.  } bind def
  130.  
  131. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  132. /.numcopiesdict mark
  133.   /NumCopies dup
  134. .dicttomark readonly def
  135.  
  136. /.currentnumcopies
  137.  { currentdevice //.numcopiesdict .getdeviceparams
  138.    dup type /integertype eq
  139.     { exch pop exch pop }
  140.     { cleartomark #copies }
  141.    ifelse
  142.  } bind odef
  143.  
  144. % ---------------- Auxiliary definitions ---------------- %
  145.  
  146. % Define the required attributes of all page devices, and their default values.
  147. % We don't include attributes such as .MediaSize, which all devices
  148. % are guaranteed to supply on their own.
  149. /.defaultpolicies mark
  150.   /PolicyNotFound 1
  151.   /PageSize 0
  152.   /PolicyReport {pop} bind
  153. .dicttomark readonly def
  154. /.requiredattrs mark
  155.   /PageOffset [0 0] readonly
  156. % We define InputAttributes and OutputAttributes with a single
  157. % dummy media type that handles pages of any size.
  158. % Devices that care will override this.
  159.   /InputAttributes mark 0
  160.     mark /PageSize [0 dup 16#7ffff dup] .dicttomark readonly
  161.   .dicttomark readonly
  162.   (%MediaSource) 0
  163.   /OutputAttributes mark 0
  164.     mark .dicttomark readonly
  165.   .dicttomark readonly
  166.   (%MediaDestination) 0
  167.   /Install {.callinstall} bind
  168.   /BeginPage {.callbeginpage} bind
  169.   /EndPage {.callendpage} bind
  170.   /Policies .defaultpolicies
  171. .dicttomark readonly def
  172.  
  173. % Define currentpagedevice so it creates the dictionary on demand if needed,
  174. % adding all the required entries defined just above.
  175. % We have to deal specially with entries that the driver may change
  176. % on its own.
  177. /.dynamicppkeys mark
  178.   /.MediaSize dup        % because it changes when PageSize is set
  179.   /PageCount dup
  180. .dicttomark readonly def
  181. /.makecurrentpagedevice        % - .makecurrentpagedevice <dict>
  182.  { currentdevice null .getdeviceparams
  183.     % In case of duplicate keys, .dicttomark takes the entry
  184.     % lower on the stack, so we can just append the defaults here.
  185.    .requiredattrs { } forall .dicttomark
  186.    dup .setpagedevice
  187.  } bind def
  188. /currentpagedevice
  189.  { .currentpagedevice
  190.     { dup length 0 eq
  191.        { pop .makecurrentpagedevice
  192.        }
  193.        {    % If any of the dynamic keys have changed,
  194.         % we must update the page device dictionary.
  195.      currentdevice //.dynamicppkeys .getdeviceparams .dicttomark
  196.       {    % Stack: current key value
  197.         2 index 2 index .knownget { 1 index ne } { true } ifelse
  198.          { 2 index wcheck not
  199.         {    % This is the first entry being updated.
  200.             % Copy the dictionary to make it writable.
  201.           3 -1 roll dup length dict .copydict
  202.           3 1 roll
  203.         }
  204.            if
  205.            2 index 3 1 roll put
  206.          }
  207.          { pop pop
  208.          }
  209.         ifelse
  210.       }
  211.      forall
  212.         % We would like to do a .setpagedevice so we don't keep
  213.         % re-creating the dictionary.  Unfortunately, the effect
  214.         % of this is that if any dynamic key changes (PageCount
  215.         % in particular), we will do the equivalent of a
  216.         % setpagedevice at the next restore or grestore.
  217.         % Therefore, we make the dictionary read-only, but
  218.         % we don't store it away.  I.e., NOT:
  219.         % dup wcheck { .setpagedevice .currentpagedevice pop } if
  220.      readonly
  221.        }
  222.       ifelse
  223.     }
  224.    if
  225.  } bind odef
  226.  
  227. % The implementation of setpagedevice is quite complex.  Currently,
  228. % everything but the media matching algorithm is implemented here.
  229.  
  230. % By default, we only present the requested changes to the device,
  231. % but there are some parameters that require special merging action.
  232. % Define those parameters here, with the procedures that do the merging.
  233. % The procedures are called as follows:
  234. %    <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  235. /.mergespecial mark
  236.   /InputAttributes
  237.    { dup null eq
  238.       { pop null
  239.       }
  240.       { 3 copy pop .knownget
  241.      { dup null eq
  242.         { pop dup length dict }
  243.         { dup length 2 index length add dict .copydict }
  244.        ifelse
  245.      }
  246.      { dup length dict
  247.      }
  248.         ifelse .copydict readonly
  249.       }
  250.      ifelse
  251.    } bind
  252.   /OutputAttributes 1 index
  253.   /Policies
  254.     { 3 copy pop .knownget
  255.        { dup length 2 index length add dict .copydict }
  256.        { dup length dict }
  257.       ifelse copy readonly
  258.     } bind
  259. .dicttomark readonly def
  260.  
  261. % Define the keys used in input attribute matching.
  262. /.inputattrkeys [
  263.   /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
  264.     % The following are documented in Adobe's supplement for v2017.
  265.   /LeadingEdge /MediaClass
  266. ] readonly def
  267. % Define other keys used in media selection.
  268. /.inputselectionkeys [
  269.   /MediaPosition /Orientation
  270. ] readonly def
  271.  
  272. % Define the keys used in output attribute matching.
  273. /.outputattrkeys [
  274.   /OutputType
  275. ] readonly def
  276.  
  277. % Define all the parameters that should always be copied to the merged
  278. % dictionary.
  279. /.copiedkeys [
  280.   /OutputDevice
  281.   .mergespecial { pop } forall
  282.   .inputattrkeys aload pop
  283.   .inputselectionkeys aload pop
  284.   .outputattrkeys aload pop
  285. ] readonly def
  286.  
  287. % Define the parameters that should not be presented to the device.
  288. % The procedures are called as follows:
  289. %    <merged> <key> <value> -proc-
  290. % The procedure leaves all its operands on the stack and returns
  291. % true iff the key/value pair should be presented to .putdeviceparams.
  292. /.presentspecial mark
  293.   .dynamicppkeys { pop false } forall
  294.             % We must ignore an explicit request for .MediaSize,
  295.             % because media matching always handles this.
  296.   /.MediaSize false
  297.   /Name false
  298.   /OutputDevice false
  299.   /PageOffset false
  300.   /PageSize false        % obsolete alias for .MediaSize
  301.   /InputAttributes false
  302.   .inputattrkeys
  303.     { dup /PageSize eq
  304.        { pop }
  305.        { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
  306.       ifelse
  307.     }
  308.   forall
  309.   .inputselectionkeys { false } forall
  310.   /OutputAttributes false
  311.   .outputattrkeys
  312.     { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
  313.   forall
  314.   /Install false
  315.   /BeginPage false
  316.   /EndPage false
  317.   /Policies false
  318.     % Our extensions:
  319.   /HWColorMap
  320.     {            % HACK: don't transmit the color map, because
  321.             % window systems can change the color map on their own
  322.             % incrementally.  Someday we'll have a better
  323.             % solution for this....
  324.       false
  325.     }
  326.   /ViewerPreProcess false
  327. .dicttomark readonly def
  328.  
  329. % Define access to device defaults.
  330. /.defaultdeviceparams
  331.  { finddevice null .getdeviceparams
  332.  } bind def
  333.  
  334. % Select media (input or output).  The hard work is done in an operator:
  335. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  336. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  337. %    <pagedict> null <policydict> <keys> .matchmedia null true
  338. /.selectmedia        % <orig> <request> <merged> <failed>     <-- retained
  339.             %   <attrdict> <policydict> <attrkeys> <mediakey>
  340.             %   .selectmedia
  341.  { 5 index 5 -2 roll 4 index .matchmedia
  342.         % Stack: orig request merged failed attrkeys mediakey
  343.         %   (key true | false)
  344.     { 4 index 3 1 roll put pop
  345.     }
  346.     {    % Adobe's implementations have a "big hairy heuristic"
  347.     % to choose the set of keys to report as having failed the match.
  348.     % For the moment, we report any keys that are in the request
  349.     % and don't have the same value as in the original dictionary.
  350.       5 index 1 index .knownget
  351.        { 4 index 3 1 roll put }
  352.        { 3 index exch .undef }
  353.       ifelse
  354.        {    % Stack: <orig> <request> <merged> <failed> <attrkey>
  355.      3 index 1 index .knownget
  356.       { 5 index 2 index .knownget { ne } { pop true } ifelse }
  357.       { true }
  358.      ifelse        % Stack: ... <failed> <attrkey> <report>
  359.       { 2 copy /rangecheck put }
  360.      if pop
  361.        }
  362.       forall
  363.     }
  364.    ifelse
  365.  } bind def
  366.  
  367. % Apply Policies to any unprocessed failed requests.
  368. % As we process each request entry, we replace the error name
  369. % in the <failed> dictionary with the policy value,
  370. % and we replace the key in the <merged> dictionary with its prior value
  371. % (or remove it if it had no prior value).
  372. /.policyprocs mark
  373. % These procedures are called with the following on the stack:
  374. %   <orig> <merged> <failed> <Policies> <key> <policy>
  375. % They are expected to consume the top 2 operands.
  376. % NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
  377. % the same as 0, i.e., we signal an error.
  378.   0 {        % Set errorinfo and signal a configurationerror.
  379.     pop dup 4 index exch get 2 array astore
  380.     $error /errorinfo 3 -1 roll put
  381.     cleartomark
  382.     /setpagedevice load /configurationerror signalerror
  383.   } bind
  384.   1 {        % Roll back the failed request to its previous status.
  385. DEBUG { (Rolling back.\n) print pstack flush } if
  386.     3 index 2 index 3 -1 roll put
  387.     4 index 1 index .knownget
  388.      { 4 index 3 1 roll put }
  389.      { 3 index exch .undef }
  390.     ifelse
  391.   } bind
  392.   7 {        % For PageSize only, just impose the request.
  393.     1 index /PageSize eq
  394.      { pop pop 1 index /PageSize 7 put }
  395.      { .policyprocs 0 get exec }
  396.     ifelse
  397.   } bind
  398. .dicttomark readonly def
  399. /.applypolicies        % <orig> <merged> <failed> .applypolicies
  400.             %   <orig> <merged'> <failed'>
  401.  { 1 index /Policies get 1 index
  402.     { type /integertype eq
  403.        { pop        % already processed
  404.        }
  405.        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  406.             % Stack: <orig> <merged> <failed> <Policies> <key>
  407.             %   <policy>
  408.      .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
  409.        }
  410.       ifelse
  411.     }
  412.    forall pop
  413.  } bind def
  414.  
  415. % Prepare to present parameters to the device, by spreading them onto the
  416. % operand stack and removing any that shouldn't be presented.
  417. /.prepareparams        % <params> .prepareparams -mark- <key1> <value1> ...
  418.  { mark exch dup
  419.     {            % Stack: -mark- key1 value1 ... merged key value
  420.       .presentspecial 2 index .knownget
  421.        { exec { 3 -1 roll } { pop pop } ifelse }
  422.        { 3 -1 roll }
  423.       ifelse
  424.     }
  425.    forall pop
  426.  } bind def
  427.  
  428. % Put device parameters without resetting currentpagedevice.
  429. % (.putdeviceparams clears the current page device.)
  430. /.putdeviceparamsonly    % <device> <Policies|null> <require_all> -mark-
  431.             %   <key1> <value1> ... .putdeviceparamsonly
  432.             % On success: <device> <eraseflag>
  433.             % On failure: <device> <Policies|null> <req_all> -mark-
  434.             %   <key1> <error1> ...
  435.  { .currentpagedevice
  436.     { counttomark 4 add 1 roll .putdeviceparams
  437.       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  438.       .setpagedevice
  439.     }
  440.     { pop .putdeviceparams
  441.     }
  442.    ifelse
  443.  } bind def
  444.  
  445. % Try setting the device parameters from the merged request.
  446. /.trysetparams        % <merged> <(ignored)> <device> <Policies>
  447.             %   .trysetparams
  448.  { true 4 index .prepareparams
  449.             % Add the computed .MediaSize.
  450.             % Stack: merged (ignored) device Policies -true-
  451.             %   -mark- key1 value1 ...
  452.    counttomark 5 add index .computemediasize
  453.    exch pop exch pop /.MediaSize exch
  454. DEBUG { (Putting.\n) print pstack flush } if
  455.    .putdeviceparamsonly
  456. DEBUG { (Result of putting.\n) print pstack flush } if
  457.  } bind def
  458.  
  459. % Compute the media size and initial matrix from a merged request (after
  460. % media selection).
  461. /.computemediasize    % <request> .computemediasize
  462.             %   <request> <matrix> <[width height]>
  463.  { dup /PageSize get                    % requested page size
  464.    1 index /InputAttributes get
  465.      2 index (%MediaSource) get get /PageSize get    % media size
  466.                             % (may be a range)
  467.    2 index /Policies get
  468.      dup /PageSize .knownget
  469.       { exch pop } { /PolicyNotFound get } ifelse    % PageSize policy,
  470.                             % affects scaling
  471.    3 index /Orientation .knownget not { null } if
  472.    4 index /RollFedMedia .knownget not { false } if
  473.    matrix .matchpagesize pop        % (can't fail)
  474.    2 array astore
  475.  } bind def
  476.  
  477. % ---------------- setpagedevice itself ---------------- %
  478.  
  479. /setpagedevice
  480.  {        % We mustn't pop the argument until the very end,
  481.         % so that the pseudo-operator machinery can restore the stack
  482.         % if an error occurs.
  483.    mark 1 index currentpagedevice
  484.  
  485.         % Check whether we are changing OutputDevice;
  486.         % also handle the case where the current device
  487.         % is not a page device.
  488.         % Stack: mark <request> <current>
  489. DEBUG { (Checking.\n) print pstack flush } if
  490.  
  491.    dup /OutputDevice .knownget
  492.     {        % Current device is a page device.
  493.       2 index /OutputDevice .knownget
  494.        {    % A specific OutputDevice was requested.
  495.      2 copy eq
  496.       { pop pop null }
  497.       { exch pop }
  498.      ifelse
  499.        }
  500.        { pop null
  501.        }
  502.       ifelse
  503.     }
  504.     {        % Current device is not a page device.
  505.         % Use the default device.
  506.       1 index /OutputDevice .knownget not { .defaultdevicename } if
  507.     }
  508.    ifelse
  509.    dup null eq
  510.     { pop
  511.     }
  512.     { exch pop .defaultdeviceparams
  513.         % In case of duplicate keys, .dicttomark takes the entry
  514.         % lower on the stack, so we can just append the defaults here.
  515.       .requiredattrs { } forall .dicttomark
  516.     }
  517.    ifelse
  518.  
  519.         % Check whether a viewer wants to intervene.
  520.         % We must check both the request (which takes precedence)
  521.         % and the current dictionary.
  522.         % Stack: mark <request> <orig>
  523.    exch dup /ViewerPreProcess .knownget
  524.     { exec }
  525.     { 1 index /ViewerPreProcess .knownget { exec } if }
  526.    ifelse exch
  527.  
  528.         % Construct a merged request from the actual request plus
  529.         % any keys that should always be propagated.
  530.         % Stack: mark <request> <orig>
  531. DEBUG { (Merging.\n) print pstack flush } if
  532.  
  533.    exch 1 index length 1 index length add dict
  534.    .copiedkeys
  535.     {        % Stack: <orig> <request> <merged> <key>
  536.       3 index 1 index .knownget { 3 copy put pop } if pop
  537.     }
  538.    forall
  539.         % Stack: <orig> <request> <merged>
  540.    dup 2 index
  541.     {        % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  542.       .mergespecial 2 index .knownget { exec } if
  543.       put dup
  544.     }
  545.    forall pop
  546.         % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  547.         % change HWResolution.
  548.    FIXEDRESOLUTION { dup /HWResolution .undef } if
  549.         % Hack: if FIXEDMEDIA is true, discard any attempt to change
  550.         % PageSize or HWSize.
  551.    FIXEDMEDIA
  552.     { dup /PageSize 4 index /PageSize get put
  553.       dup /HWSize 4 index /HWSize get put
  554.     } if
  555.  
  556.         % Select input and output media.
  557.         % Stack: mark <orig> <request> <merged>
  558. DEBUG { (Selecting.\n) print pstack flush } if
  559.  
  560.    0 dict    % <failed>
  561.    1 index /InputAttributes .knownget
  562.     { 2 index /Policies get
  563.       .inputattrkeys (%MediaSource) cvn .selectmedia
  564.     } if
  565.    1 index /OutputAttributes .knownget
  566.     { 2 index /Policies get
  567.       .outputattrkeys (%MediaDestination) cvn .selectmedia
  568.      } if
  569.    3 -1 roll 4 1 roll        % temporarily swap orig & request
  570.    .applypolicies
  571.    3 -1 roll 4 1 roll        % swap back
  572.  
  573.         % Construct the new device, and attempt to set its attributes.
  574.         % Stack: mark <orig> <request> <merged> <failed>
  575. DEBUG { (Constructing.\n) print pstack flush } if
  576.  
  577.    currentdevice .devicename 2 index /OutputDevice get eq
  578.     { currentdevice }
  579.     { 1 index /OutputDevice get finddevice }
  580.    ifelse
  581.         %**************** We should copy the device here,
  582.         %**************** but since we can't close the old device,
  583.         %**************** we don't.  This is WRONG.
  584.     %****************copydevice
  585.    2 index /Policies get
  586.    .trysetparams
  587.    dup type /booleantype ne
  588.     {        % The request failed.
  589.         % Stack: ... <orig> <request> <merged> <failed> <device>
  590.         %   <Policies> true mark <name> <errorname> ...
  591. DEBUG { (Recovering.\n) print pstack flush } if
  592.       counttomark 4 add index
  593.       counttomark 2 idiv { dup 4 -2 roll put } repeat
  594.       pop pop pop
  595.         % Stack: mark ... <orig> <request> <merged> <failed> <device>
  596.         %   <Policies>
  597.       6 2 roll 3 -1 roll 4 1 roll
  598.       .applypolicies
  599.       3 -1 roll 4 1 roll 6 -2 roll
  600.       .trysetparams        % shouldn't fail!
  601.       dup type /booleantype ne
  602.        { 2 { counttomark 1 add 1 roll cleartomark } repeat
  603.          /setpagedevice load exch signalerror
  604.        }
  605.       if
  606.     }
  607.    if
  608.  
  609.         % The attempt succeeded.  Install the new device.
  610.         % Stack: mark ... <merged> <failed> <device> <eraseflag>
  611. DEBUG { (Installing.\n) print pstack flush } if
  612.  
  613.    pop 2 .endpage
  614.     { 1 true .outputpage
  615.       (>>setpagedevice, press <return> to continue<<\n) .confirm
  616.     }
  617.    if
  618.         % .setdevice clears the current page device!
  619.    .currentpagedevice pop exch
  620.    .setdevice pop
  621.    .setpagedevice
  622.  
  623.         % Merge the request into the current page device.
  624.         % Stack: mark ... <merged> <failed>
  625.    exch currentpagedevice dup length 2 index length add dict
  626.    .copydict .copydict
  627.         % Initialize the default matrix, taking media matching
  628.         % into account.
  629.    .computemediasize pop initmatrix concat
  630.    dup /PageOffset .knownget
  631.     {        % Translate by the given number of 1/72" units in device X/Y.
  632.       dup 0 get exch 1 get
  633.       2 index /HWResolution get dup 1 get exch 0 get
  634.       4 -1 roll mul 72 div   3 1 roll mul 72 div
  635.       idtransform translate
  636.     }
  637.    if
  638.         % We must install the new page device dictionary
  639.         % before calling the Install procedure.
  640.    dup .setpagedevice
  641.    .setdefaultscreen    % Set the default screen before calling Install.
  642.    dup /Install .knownget { exec } if
  643.    matrix currentmatrix .setdefaultmatrix
  644.         % Erase and initialize the page.
  645.    erasepage initgraphics
  646.    .beginpage
  647.  
  648.         % Clean up, calling PolicyReport if needed.
  649.         % Stack: mark ... <failed> <merged>
  650. DEBUG { (Finishing.\n) print pstack flush } if
  651.  
  652.    exch dup length 0 ne
  653.     { 1 index /Policies get /PolicyReport get
  654.       counttomark 1 add 2 roll cleartomark
  655.       exec
  656.     }
  657.     { cleartomark
  658.     }
  659.    ifelse pop
  660.  
  661.  } odef
  662.  
  663. end                % level2dict
  664. .setlanguagelevel
  665.